﻿// ----------------------------------------------------------------------------------
// Sample Code from Fernando Machado Píriz's blog: http://fernandomachadopiriz.com
//
// <copyright company="Fernando Machado Píriz" file="DesktopBackground.cs">
// Copyright (c) Fernando Machado Píriz. Distributed under FSF's GPL v2.</copyright>
// ----------------------------------------------------------------------------------
// This code and information are provided "as is" without warranty of any kind,
// either expressed of implied, including but not limited to the implied warranties
// of merchantability and/or fitness for a particular purpose.
// ----------------------------------------------------------------------------------
namespace DesktopBackground
{
    using System;
    using System.Globalization;
    using System.Runtime.InteropServices;
    using System.Security.AccessControl;
    using Microsoft.Win32;

    /// <summary>
    /// Provides access to desktop background properties.
    /// </summary>
    public static class DesktopBackgroundHelper
    {
        /// <summary>
        /// The name of the Windows Registry key storing desktop background properties.
        /// </summary>
        private const string DesktopKeyName = @"Control Panel\Desktop";

        /// <summary>
        /// The name of the Windows Registry value storing desktop background file.
        /// </summary>
        private const string WallpaperValueName = "Wallpaper";

        /// <summary>
        /// The name of the Windows Registry value storing desktop background tile configuration.
        /// </summary>
        private const string TileWallpaperValueName = "TileWallpaper";

        /// <summary>
        /// The name of the Windows Registry value storing desktop background style configuration.
        /// </summary>
        private const string WallpaperStyleValueName = "WallpaperStyle";

        /// <summary>
        /// Gets or sets the desktop background file.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults",
            MessageId = "DesktopBackground.DesktopBackgroundHelper+NativeMethods.SystemParametersInfo(System.Int32,System.Int32,System.String,System.Int32)", Justification = "No need or no way to process return value")]
        public static string Wallpaper
        {
            get
            {
                return DesktopBackgroundHelper.GeStringValue(WallpaperValueName);
            }

            set
            {
                NativeMethods.SystemParametersInfo(NativeMethods.SPI_SETDESKWALLPAPER, 0, value, 0); 
            }
        }

        /// <summary>
        /// Gets or sets the desktop background tile configuration. This value is stored in the Windows Registry as REG_SZ with value 0 or 1 so it
        /// is read as int and written as string.
        /// </summary>
        public static int TileWallpaper
        {
            get
            {
                return DesktopBackgroundHelper.GetIntValue(TileWallpaperValueName);
            }

            set
            {
                DesktopBackgroundHelper.SetStringValue(TileWallpaperValueName, value.ToString(CultureInfo.InvariantCulture));
            }
        }

        /// <summary>
        /// Gets or sets the desktop background style configuration. This value is stored in the Windows Registry as REG_SZ with value 0 or 1 so it
        /// is read as int and written as string.
        /// </summary>
        public static int WallpaperStyle
        {
            get
            {
                return DesktopBackgroundHelper.GetIntValue(WallpaperStyleValueName);
            }

            set
            {
                DesktopBackgroundHelper.SetStringValue(WallpaperStyleValueName, value.ToString(CultureInfo.InvariantCulture));
            }
        }

        /// <summary>
        /// Reads an int from the given value in the <code>DesktopKeyName</code> Windows Registry key.
        /// </summary>
        /// <param name="valueName">The name of the value to read.</param>
        /// <returns>The value read from the registry.</returns>
        private static int GetIntValue(string valueName)
        {
            int result = default(int);

            RegistryKey hkcu = Registry.CurrentUser;
            RegistryKey desktopKey = hkcu.OpenSubKey(DesktopKeyName);
            try
            {
                object value = desktopKey.GetValue(valueName);

                if (value != null)
                {
                    result = Convert.ToInt32(value, CultureInfo.InvariantCulture);
                }
            }
            finally
            {
                desktopKey.Close();
            }

            return result;
        }

        /// <summary>
        /// Writes an int into the given value in the <code>DesktopKeyName</code> Windows Registry key.
        /// </summary>
        /// <param name="valueName">The name of the value to write.</param>
        /// <param name="value">The value to write.</param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode",
            Justification = "May be useful in the future")]
        private static void SetIntValue(string valueName, int value)
        {
            RegistryKey hkcu = Registry.CurrentUser;
            RegistryKey desktopKey = hkcu.OpenSubKey(DesktopKeyName, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.FullControl);
            try
            {
                desktopKey.SetValue(valueName, value);
            }
            finally
            {
                desktopKey.Close();
            }
        }

        /// <summary>
        /// Reads a string from the given value in the <code>DesktopKeyName</code> Windows Registry key.
        /// </summary>
        /// <param name="valueName">The name of the value to read.</param>
        /// <returns>The value read from the registry.</returns>
        private static string GeStringValue(string valueName)
        {
            string result = null;
            RegistryKey hkcu = Registry.CurrentUser;
            RegistryKey desktopKey = hkcu.OpenSubKey(DesktopKeyName);
            try
            {
                var value = desktopKey.GetValue(valueName);

                if (value != null)
                {
                    result = value.ToString();
                }
            }
            finally
            {
                desktopKey.Close();
            }

            return result;
        }

        /// <summary>
        /// Writes a string into the given value in the <code>DesktopKeyName</code> Windows Registry key.
        /// </summary>
        /// <param name="valueName">The name of the value to write.</param>
        /// <param name="value">The value to write.</param>
        private static void SetStringValue(string valueName, string value)
        {
            RegistryKey hkcu = Registry.CurrentUser;
            RegistryKey desktopKey = hkcu.OpenSubKey(DesktopKeyName, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.FullControl);
            try
            {
                desktopKey.SetValue(valueName, value);
            }
            finally
            {
                desktopKey.Close();
            }
        }

        /// <summary>
        /// Win32 API imports.
        /// </summary>
        internal static class NativeMethods
        {
            /// <summary>
            /// Changes the desktop background.
            /// </summary>
            internal const int SPI_SETDESKWALLPAPER = 20;

            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            internal static extern int SystemParametersInfo(
                int uAction, int uParam, [MarshalAs(UnmanagedType.LPWStr)]string lpvParam, int fuWinIni);
        }
    }
}